
#include <assert.h>
#include <stdlib.h>
#include "utility.h"
#include "qr-const.h"
#include "qr-common.h"

static int make_mask_pattern0(int width, unsigned char* source, unsigned char* masked);
static int make_mask_pattern1(int width, unsigned char* source, unsigned char* masked);
static int make_mask_pattern2(int width, unsigned char* source, unsigned char* masked);
static int make_mask_pattern3(int width, unsigned char* source, unsigned char* masked);
static int make_mask_pattern4(int width, unsigned char* source, unsigned char* masked);
static int make_mask_pattern5(int width, unsigned char* source, unsigned char* masked);
static int make_mask_pattern6(int width, unsigned char* source, unsigned char* masked);
static int make_mask_pattern7(int width, unsigned char* source, unsigned char* masked);

unsigned char* make_mask(int version, MaskPattern mask_pattern, unsigned char* frame)
{
	int width;
	unsigned char* masked;

	if(qr_check_version(version) < 0 || qr_check_mask_pattern(mask_pattern) < 0 || NULL == frame)
	{
		RES_NULL("Argument is invalid.");
	}

	width = qr_width(version);
	if(width <= 0)
	{
		RES_NULL("Invoke qr_width error.");
	}
	masked = (unsigned char*)malloc(width * width * sizeof(unsigned char));
	if(NULL == masked)
	{
		RES_NULL("Invoke malloc error.");
	}
	switch(mask_pattern)
	{
		case MASK_PATTERN0:
			{
				make_mask_pattern0(width, frame, masked);
			}
			break;
		case MASK_PATTERN1:
			{
				make_mask_pattern1(width, frame, masked);
			}
			break;
		case MASK_PATTERN2:
			{
				make_mask_pattern2(width, frame, masked);
			}
			break;
		case MASK_PATTERN3:
			{
				make_mask_pattern3(width, frame, masked);
			}
			break;
		case MASK_PATTERN4:
			{
				make_mask_pattern4(width, frame, masked);
			}
			break;
		case MASK_PATTERN5:
			{
				make_mask_pattern5(width, frame, masked);
			}
			break;
		case MASK_PATTERN6:
			{
				make_mask_pattern6(width, frame, masked);
			}
			break;
		case MASK_PATTERN7:
			{
				make_mask_pattern7(width, frame, masked);
			}
			break;
		default:
			{
				assert(FALSE);
			}
			break;
	}
	return masked;
}


#define MASK_MAKER(exp) \
	int x, y, black_count; \
\
	assert(width > 0 && source != NULL && masked != NULL); \
\
	black_count = 0; \
	for(y = 0; y < width; ++y) \
	{ \
		for(x = 0; x < width; ++x) \
		{ \
			if(0 == (*source & 0x80)) \
			{ \
				*masked = *source ^ (0 == (exp)); \
			} \
			else \
			{ \
				*masked = *source; \
			} \
			if((*masked & 1) != 0) \
			{ \
				assert(1 == (*masked & 1)); \
				++black_count; \
			} \
			++source; \
			++masked; \
		} \
	} \
	return black_count;

int make_mask_pattern0(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER((x + y) & 1)
}

int make_mask_pattern1(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER(y & 1)
}

int make_mask_pattern2(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER(x % 3)
}

int make_mask_pattern3(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER((x + y) % 3)
}

int make_mask_pattern4(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER(((y >> 1) + (x / 3)) & 1)
}

int make_mask_pattern5(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER(((x * y) & 1) + ((x * y) % 3))
}

int make_mask_pattern6(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER((((x * y) & 1) + ((x * y) % 3)) & 1)
}

int make_mask_pattern7(int width, unsigned char* source, unsigned char* masked)
{
	MASK_MAKER((((x * y) % 3) + ((x + y) & 1)) & 1)
}

